#include "Gwen/Controls.h"
#include "Gwen/Controls/MenuStrip.h"
#include "StompedReality/Core/FileSystem.h"
#include "StompedReality/Core/Graphics/RenderSystem.h"
#include "StompedReality/Core/IGame.h"
#include "StomperLib/BaseLayout.h"
#include "StomperLib/Controls/ToolWindow.h"
#include "StomperLib/ToolElement.h"
#include <Gwen/Controls/Dialogs/FileOpen.h>
#include <Gwen/Controls/Dialogs/FileSave.h>
#include <algorithm>
#include <assert.h>
namespace StomperLib {
BaseLayout::BaseLayout( Gwen::Controls::Canvas* canvas )
  : Gwen::Controls::Base( canvas, "RootDock" ), StompedReality::GameAccess( )
{
  Dock( Gwen::Pos::Fill );
  SetPadding( Gwen::Padding( 0, 0, 0, 0 ));

  Gwen::Controls::Base* base = new Gwen::Controls::Base( this );
  base->Dock( Gwen::Pos::Fill );

  base->onHoverEnter.Add( this, &BaseLayout::OnMouseEditAreaEnter );
  base->onHoverLeave.Add( this, &BaseLayout::OnMouseEditAreaLeave );
  base->onHoverEnter.Add( this, &BaseLayout::Focus );

  m_Camera = new EditorCamera( );
}

void BaseLayout::CreateBaseElements( )
{
  assert( this->m_Game != NULL );

  this->SetBounds( 0, 0, this->m_Game->RenderSystem( )->GetWidth( ), this->m_Game->RenderSystem( )->GetHeight( ));

  this->CreateMenuStrip( );
  this->CreateNewProjectOverlay( );

  this->m_EditorProperties = NULL;

  this->m_EditorProperties = this->m_Game->getFileSystem( )->openAsJson( "Content/Properties.json" );

  this->OnCreateBaseElements( );
}

BaseLayout::~BaseLayout( )
{
  if (m_Camera)
  {
    delete m_Camera;
    m_Camera = NULL;
  }
}

void BaseLayout::Render( Gwen::Skin::Base* skin )
{
  if (m_MouseInEditorArea)
  {
    std::sort( this->m_Elements.begin( ), this->m_Elements.end( ),
               [] (StomperLib::ToolElement* a, StomperLib::ToolElement* b)->int
               {
                 return b->UpdateOrder > a->UpdateOrder;
               } );
    for (auto iter = this->m_Elements.begin( ); iter != this->m_Elements.end( ); ++iter)
    {
      if ((*iter)->Update( ))
        break;
    }
  }

  glPushMatrix( );
  glTranslatef( m_Camera->GetTranslation( ).GetX( ), m_Camera->GetTranslation( ).GetY( ), 0 );

  std::sort( this->m_Elements.begin( ), this->m_Elements.end( ),
             [] (StomperLib::ToolElement* a, StomperLib::ToolElement* b)->int
             {
               return b->DrawOrder > a->DrawOrder;
             } );

  for (auto iter = this->m_Elements.begin( ); iter != this->m_Elements.end( ); ++iter)
  {
    (*iter)->Draw( );
  }

  glPopMatrix( );
}

void BaseLayout::AddToolElement( StomperLib::ToolElement* element )
{
  this->m_Elements.push_back( element );
}

void BaseLayout::CreateMenuStrip( )
{
  Gwen::Controls::MenuStrip* m_MenuStrip = new Gwen::Controls::MenuStrip( this );
  m_MenuStrip->Dock( Gwen::Pos::Top );

  Gwen::Controls::MenuItem* fileMenu = m_MenuStrip->AddItem( "File" );

  //Gwen::Controls::MenuItem* projectMenu = fileMenu->GetMenu( )->AddItem( L"Project" );

  fileMenu->GetMenu( )->AddItem( L"New Project", "EditorBase/img/New.png", "Ctrl + n" )->SetAction(
    this, &BaseLayout::OnCreateProjectClick );
  fileMenu->GetMenu( )->AddItem( L"Open Project", "EditorBase/img/Open.png", "Ctrl + o" )->SetAction(
    this, &BaseLayout::OnOpenProjectClick );
  fileMenu->GetMenu( )->AddItem( L"Save Project", "EditorBase/img/Save.png", "Ctrl + s" )->SetAction(
    this, &BaseLayout::OnSaveProjectClick );
  fileMenu->GetMenu( )->AddItem( L"Save Layout", "EditorBase/img/Save.png", "Ctrl + Shift + s" )->SetAction(
    this, &BaseLayout::OnSaveLayoutClick );

  m_WindowMenu = m_MenuStrip->AddItem( "View" );
}

void BaseLayout::CreateNewProjectOverlay( )
{
  m_NewProject = new StomperLib::Controls::NewProject( this );
  m_NewProject->Dock( Gwen::Pos::Fill );
  m_NewProject->SetGame( this->m_Game );
  m_NewProject->onCreateProject.Add( this, &BaseLayout::OnCreateProject );
  m_NewProject->Hide( );
}

StomperLib::Controls::ToolWindow* BaseLayout::CreateSubWindow( Gwen::String title, Gwen::String accelerator,
                                                               bool toggled )
{
  auto window = new StomperLib::Controls::ToolWindow( this );
  window->SetTitle( title );
  window->SetName( title );

  window->onWindowClosed.Add( this, &BaseLayout::OnWindowCloseClick );
  window->onHoverEnter.Add( this, &BaseLayout::OnMouseEditAreaLeave );
  window->onHoverLeave.Add( this, &BaseLayout::OnMouseEditAreaEnter );

  Gwen::Controls::MenuItem* menuItem = this->CreateSubWindowMenuItem( title, accelerator, toggled );

  if (this->m_EditorProperties)
    window->ParseProperties( *(this->m_EditorProperties));

  return window;
}

Gwen::Controls::MenuItem* BaseLayout::CreateSubWindowMenuItem( Gwen::String title, Gwen::String accelerator,
                                                               bool toggled )
{
  Gwen::Controls::MenuItem* menuItem = this->m_WindowMenu->GetMenu( )->AddItem( title );
  menuItem->SetCheckable( true );
  menuItem->SetName( title );
  menuItem->onCheckChange.Add( this, &BaseLayout::OnWindowToggleChange );
  menuItem->SetChecked( toggled );

  if (!accelerator.empty( ))
    menuItem->AddAccelerator( accelerator );

  return menuItem;
}

void BaseLayout::OnCreateProjectClick( )
{
  m_NewProject->Show( );
  m_NewProject->BringToFront( );
}

void BaseLayout::OnOpenProjectClick( )
{
  Gwen::Dialogs::FileOpen( true, "OpenProject", "", "Project(*.srprj)|*.srprj", this, &BaseLayout::OpenDialogCallback );
}

void BaseLayout::OnSaveProjectClick( )
{
  this->onSaveProject.Call( this );
}

void BaseLayout::OpenDialogCallback( Gwen::Event::Info info )
{
  this->OpenProject( info.String.Get( ));
}

void BaseLayout::OnCreateProject( Gwen::Event::Info info )
{
  this->onCreateProject.Call( this, info );
  this->OpenProject( info.String.Get( ) );
}

void BaseLayout::OpenProject( Gwen::String projectFile )
{
  Gwen::Event::Information openInfo;
  openInfo.String = projectFile;
  this->onOpenProject.Call( this, openInfo );
  this->LoadLayout( );

}

void BaseLayout::OnMouseEditAreaEnter( )
{
  this->Focus( );
  this->m_MouseInEditorArea = true;
  this->onMouseEditAreaEnter.Call( this );
}

void BaseLayout::OnMouseEditAreaLeave( )
{
  this->m_MouseInEditorArea = false;
  this->onMouseEditAreaLeave.Call( this );
}

void BaseLayout::OnWindowToggleChange(  Gwen::Event::Info info )
{
  Gwen::Controls::WindowControl* window = this->FindChild<Gwen::Controls::WindowControl>( info.Control->GetName( ));
  Gwen::Controls::MenuItem* menuItem = gwen_cast<Gwen::Controls::MenuItem>( info.Control );

  assert( window != NULL );
  assert( menuItem != NULL );

  window->SetHidden( !menuItem->GetChecked( ) );
}

void BaseLayout::OnWindowCloseClick(  Gwen::Event::Info info )
{
  Gwen::Controls::MenuItem* menuItem = this->m_WindowMenu->GetMenu( )->FindChild<Gwen::Controls::MenuItem>(
      info.Control->GetName( ), true );

  assert( menuItem != NULL );

  menuItem->SetToggleState( false );
}

void BaseLayout::OnSaveLayoutClick( )
{
  Json::Value root;
  root["Editor Properties"] = Json::Value( );
  root["Editor Properties"]["Tool Windows"] = Json::Value( );
  for (auto windowItem =  m_WindowMenu->GetMenu( )->GetChildren( ).begin( );
       windowItem !=  m_WindowMenu->GetMenu( )->GetChildren( ).end( ); ++windowItem)
  {

    auto window = this->FindChild<StomperLib::Controls::ToolWindow>((*windowItem)->GetValue( ));

    if (window == NULL)
      continue;

    window->SaveProperties( root["Editor Properties"]["Tool Windows"] );
  }

  //root["Editor Properties"]["Window"]["Width"] = this->m_Game->RenderSystem()->GetWidth();
  //root["Editor Properties"]["Window"]["Height"] = this->m_Game->RenderSystem()->GetHeight();

  this->m_Game->getFileSystem( )->saveJson( root, "UserProperties.json" );
}

void BaseLayout::LoadLayout( )
{
  if (!m_Game->getFileSystem( )->existsFile( "UserProperties.json" ))
    return;

  this->m_EditorProperties  = this->m_Game->getFileSystem( )->openAsJson( "UserProperties.json" );

  for (auto windowItem =  m_WindowMenu->GetMenu( )->GetChildren( ).begin( );
       windowItem !=  m_WindowMenu->GetMenu( )->GetChildren( ).end( ); ++windowItem)
  {

    auto window = this->FindChild<StomperLib::Controls::ToolWindow>((*windowItem)->GetValue( ));

    if (window == NULL)
      continue;

    window->ParseProperties( *m_EditorProperties );
  }
}

}
